<?php
/**
 * DMFramework
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @url http://dmframework.nl
 */

/**
 * The request class can be used to calculate a controller, action, module e.t.c. from a 
 * plain request. You can also set another controller or action.
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @package System.Core
 */
class Dmf_Request
{
    /**
     * The controller
     * 
     * @var string
     */
    private $_controller;
    
    /**
     * The action
     * 
     * @var string
     */
    private $_action;
    
    /**
     * All parameters
     * 
     * @var array 
     */
    private $_parameters = array();
    
    /**
     * The module
     * 
     * @var string 
     */
    private $_module;
    
    /**
     * The request
     * 
     * @var string 
     */
    private $_request;
    
    /**
     * The configuration object
     * 
     * @var Object
     */
    private $_config;
    
    /**
     * All get parameters
     * 
     * @var array
     */
    private $_getParams;
    
    /**
     * Create request from router array
     * 
     * @param string $module
     * @param string $controller
     * @param string $action
     * @param array $parameters 
     */
    public static function fromRoute( $controller, $action, $parameters = array(), $module = false )
    {
        if ( is_array( $module ) )
        {
            $module = false;
            $parameters = array();
        }
        
        return new Dmf_Request( ( $module === false ? '' : $module . '/' ) . $controller . '/' . $action . ( count( $parameters ) > 0 ? implode( '/', $parameters ) : '' ) );
    }
    
    /**
     * Constructor 
     * 
     * @param string $request 
     */
    public function __construct( $request )
    {
        $this->_config = Dmf_Application::getInstance()->getConfig()->asObject();
        
        $request = explode( '/', $request );
        
        //Calculate controller, action and parameters
        $this->_controller = isset( $request['0'] ) ? $request['0'] : $this->_config->application->controller;
        $this->_action = isset( $request['1'] ) ? $request['1'] : $this->_config->application->action;
        $this->_controller = ( $this->_controller == null ) ? $this->_config->application->controller : $this->_controller;
        $this->_action = ( $this->_action == null ) ? $this->_config->application->action : $this->_action;
        
        unset( $request['0'] );
        unset( $request['1'] );
        
        if ( strstr( $this->_action, '?' ) )
        {
            $parts = explode( '?', $this->_action );
            $this->_action = $parts['0'];
        }
        
        if ( strstr( $this->_controller, '?' ) )
        {
            $parts = explode( '?', $this->_controller );
            $this->_controller = $parts['0'];
        }
        
        if ( isset( $parts ) )
        {
            $this->_getParams = @parse_str( $parts['1'] );
        }
        
        $this->_parameters = array_values( array_filter( $request ) );
        $this->_request = ( $this->_module == null ? '' : $this->_module . '/' ) . $this->_controller . '/' . $this->_action . ( count( $this->_parameters ) > 0 ? '/' . implode( '/', $this->_parameters ) : null );
        
        if ( $this->_config->modules->enabled && isset( $this->_config->modules->active ) )
        {
            $this->_checkForModules();
        }
    }
    
    /**
     * Recalculate request string from new string
     * 
     * @param string $requestString 
     */
    public function recalculate( $requestString )
    {
        $this->_controller = null;
        $this->_module = null;
        $this->_action = null;
        $this->_parameters = array();
        $this->_request = null;
        
        $this->__construct( $requestString );
    }
    
    /**
     * Clean the request
     * 
     * @param string $request
     * @return string 
     */
    public static function cleanRequest( $request )
    {
        //Remove the public-path from the request
        $script_name = array_values( array_filter( explode( '/', dirname( $_SERVER['SCRIPT_NAME'] ) ) ) );
        $query_string = array_values( array_filter( explode( '/', $request ) ) );
        $request = '';

        for ( $i = 0; $i < count( $query_string ); ++$i )
        {
            if ( isset( $script_name[ $i ] ) && $script_name[ $i ] == $query_string[ $i ] ) continue;

            if ( isset( $script_name[ $i ] ) && $script_name[ $i ] != $query_string[ $i ] )
            {
                unset( $script_name[ $i ] );
                $script_name = array_values( array_filter( $script_name ) );
            }

            $request .= $query_string[ $i ] . '/';
        }
        
        if ( substr( $request, 0, 1 ) == '/' )
        {
            $request = substr( $request, 1 );
        }
        
        if ( substr( $request, -1, strlen( $request ) ) == '/' )
        {
            $request = substr( $request, 0, -1 );
        }
        
        return $request;
    }
    
    /**
     * Check for available modules in the request 
     */
    private function _checkForModules()
    {
        $modules = array_values( $this->_config->modules->active->asArray() );
            
        if ( ( $key = array_search( strtolower( $this->_controller ), $modules ) ) !== false )
        {
            if ( is_dir( 'application/modules/' . $modules[ $key ] . '/' ) )
            {
                $this->loadModule();
                
                $autoloader = Dmf_Application::getInstance()->getAutoloader();
                
                $autoloader->setControllerDirectory( 'application/modules/' . $modules[ $key ] . '/controllers/' );
                $autoloader->setModelDirectory( 'application/modules/' . $modules[ $key ] . '/models/' );
                $autoloader->setFormDirectory( 'application/modules/' . $modules[ $key ] . '/forms/' );
            }
        }
    }
    
    /**
     * Get the controller
     * 
     * @return string 
     */
    public function getController()
    {
        return ucfirst( $this->_controller );
    }
    
    /**
     * Get the action
     * 
     * @return string 
     */
    public function getAction()
    {
        return $this->_action;
    }
    
    /**
     * Get the parameters
     * 
     * @return string
     */
    public function getParameters()
    {
        foreach( $this->_parameters as $key => &$value )
        {
            $value = urldecode( $value );
        }
        
        return $this->_parameters;
    }
    
    /**
     * Set the parameters
     * 
     * @param array $parameters
     */
    public function setParameters( $parameters )
    {
        $this->_parameters = $parameters;
    }
    
    /**
     * Checks if a module is loaded 
     */
    public function moduleIsLoaded()
    {
        return ( $this->_module === false || $this->_module == null ? false : true );
    }
    
    /**
     * Get module name
     * 
     * @return string
     */
    public function getModule()
    {
        return $this->_module;
    }
    
    /**
     * Set controller
     * 
     * @param string $controller 
     */
    public function setController( $controller )
    {
        $this->_controller = $controller;
    }
    
    /**
     * Set action
     * 
     * @param string $action 
     */
    public function setAction( $action )
    {
        $this->_action = $action;
    }
    
    /**
     * Set module
     * 
     * @param string $module 
     */
    public function setModule( $module )
    {
        if ( $module === false )
        {
            $this->_module = false;
            return;
        }
        
        $this->_module = strtolower( $module );
    }
    
    /**
     * Load module 
     */
    public function loadModule()
    {
        $parameters = $this->getParameters();
        
        $this->setModule( $this->getController() );
        $this->setController( $this->getAction() );
        
        if ( isset( $parameters['0'] ) )
        {
            $this->setAction( $parameters['0'] );
            
            unset( $parameters['0'] );   
        }
        else
        {
            $this->setAction( $this->_config->application->action );
        }
        
        $this->_parameters = array_values( array_filter( $parameters ) );
    }
    
    /**
     * Get the request string
     * 
     * @var string
     */
    public function getRequest()
    {
        return $this->_request;
    }
    
    /**
     * Get current headers
     * 
     * @return array
     */
    public function headers()
    {
        if ( function_exists( 'apache_request_headers' ) ) return apache_request_headers();
        return array();
    }
    
    /**
     * Get all get query parameters
     * 
     * @return array 
     */
    public function getGetParameters()
    {
        return $this->_getParams;
    }
}